/**
 * 版权所有：厦门市巨龙信息科技有限公司
 * Copyright 2023 Xiamen Dragoninfo Eng. Co. Ltd.
 * All right reserved.
 */
package com.github.alfred.tool.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.github.alfred.tool.impl.ClientStore;
import com.google.common.collect.Lists;
import org.redisson.api.*;
import org.redisson.client.protocol.ScoredEntry;
import org.redisson.codec.SerializationCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 类说明
 *
 * @author chengh
 * @date 2023/5/17 10:51
 */
@Service
public class RedissonClientStoreImpl implements ClientStore {

    private static final Logger log = LoggerFactory.getLogger(RedissonClientStoreImpl.class);

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public boolean expire(String key, long time) {
        if (hasKey(key)) {
            return redissonClient.getBucket(key).expire(time, TimeUnit.SECONDS);
        }
        return false;
    }

    @Override
    public boolean expire(String key, Duration duration) {
        return expire(key, duration.getSeconds());
    }


    @Override
    public Long getExpire(String key) {
        return redissonClient.getBucket(key).remainTimeToLive();
    }

    @Override
    public boolean hasKey(String key) {
        return redissonClient.getBucket(key).isExists();
    }

    @Override
    public boolean del(String... key) {
        for (String k : key) {
            del(k);
        }
        return true;
    }

    @Override
    public boolean del(String key) {
        return redissonClient.getBucket(key).delete();
    }

    @Override
    public Object get(String key) {
        return redissonClient.getBucket(key).get();
    }

    @Override
    public List<Object> mGet(Collection<String> keys) {
        List<Object> list = Lists.newArrayList();
        if (CollUtil.isEmpty(keys)) {
            return list;
        }
        for (String key : keys) {
            list.add(redissonClient.getBucket(key).get());
        }
        return list;
    }

    @Override
    public boolean set(String key, Object value) {
        return set(key, value, 0);
    }

    @Override
    public boolean set(String key, Object value, int time) {

        return set(key, value, time, TimeUnit.SECONDS);
    }

    @Override
    public boolean set(String key, Object value, int time, TimeUnit timeUnit) {
        if (time <= 0) {
            return redissonClient.getBucket(key).trySet(value);
        }
        return redissonClient.getBucket(key).trySet(value, time, timeUnit);

    }

    @Override
    public Long addAndGet(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(delta);
    }

    @Override
    public Long increment(String key, long liveTime) {
        redissonClient.getAtomicLong(key).expire(liveTime, TimeUnit.SECONDS);
        return redissonClient.getAtomicLong(key).incrementAndGet();
    }


    @Override
    public void initAtomicLong(String key, Long value, long liveTime) {
        RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
        atomicLong.set(value);
        atomicLong.expire(liveTime, TimeUnit.SECONDS);
    }


    @Override
    public void resetAutoNumber(String key) {
        redissonClient.getAtomicLong(key).getAndDelete();
    }

    @Override
    public Long decr(String key, long delta) {
        return redissonClient.getAtomicLong(key).getAndAdd(-delta);

    }

    @Override
    public Object hget(String key, String item) {
        return redissonClient.getMap(key).get(item);
    }

    @Override
    public Map<Object, Object> hmget(String key) {
        return redissonClient.getMap(key).readAllMap();
    }

    @Override
    public boolean hmset(String key, Map<String, Object> map) {
        redissonClient.getMap(key).putAll(map);
        return true;
    }

    @Override
    public boolean hmset(String key, Map<String, Object> map, long time) {
        RMap<String, Object> rmap = redissonClient.getMap(key);
        rmap.putAll(map);
        return rmap.expire(time, TimeUnit.SECONDS);
    }

    @Override
    public boolean hset(String key, String item, Object value) {
        redissonClient.getMap(key).put(item, value);
        return true;
    }

    @Override
    public boolean hset(String key, String item, Object value, long time) {
        RMap<String, Object> rmap = redissonClient.getMap(key);
        rmap.put(item, value);
        return rmap.expire(time, TimeUnit.SECONDS);
    }

    @Override
    public long hdel(String key, Object... item) {
        return redissonClient.getMap(key).fastRemove(item);
    }

    @Override
    public boolean hHasKey(String key, String item) {
        return redissonClient.getMap(key).containsKey(item);
    }

    @Override
    public double hincr(String key, String item, double by) {
        return (double) redissonClient.getMap(key).addAndGet(item, by);
    }

    @Override
    public double hdecr(String key, String item, double by) {
        return (double) redissonClient.getMap(key).addAndGet(item, -by);
    }

    @Override
    public Set<Object> sGet(String key) {
        return redissonClient.getSet(key).readAll();
    }

    @Override
    public Boolean sHasKey(String key, Object value) {
        return redissonClient.getSet(key).contains(value);
    }

    @Override
    public Boolean sSet(String key, Object... values) {
        return sSetAndTime(key, 0, values);
    }

    @Override
    public List<Object> sMembers(String key) {
        Set<Object> sets = sGet(key);
        if (CollUtil.isNotEmpty(sets)) {
            return Lists.newArrayList(sets);
        }
        return Lists.newArrayList();
    }

    @Override
    public Boolean sSetAndTime(String key, long time, Object... values) {
        if (time > 0) {
            redissonClient.getSet(key).expire(time, TimeUnit.SECONDS);
        }
        return redissonClient.getSet(key).addAll(Arrays.stream(values).collect(Collectors.toSet()));
    }

    @Override
    public int sGetSetSize(String key) {
        return redissonClient.getSet(key).size();
    }

    @Override
    public boolean setRemove(String key, Object... values) {
        return redissonClient.getSet(key).removeAll(Arrays.stream(values).collect(Collectors.toSet()));
    }

    @Override
    public List<Object> lGet(String key, int start, int end) {
        return redissonClient.getList(key).range(start, end);
    }

    @Override
    public int lGetListSize(String key) {
        return redissonClient.getList(key).size();
    }

    @Override
    public Object lGetIndex(String key, int index) {
        return redissonClient.getList(key).get(index);
    }

    @Override
    public boolean lSet(String key, Object value) {
        return redissonClient.getList(key).add(value);
    }

    @Override
    public boolean lSet(String key, Object value, long time) {

        return lSet(key, Lists.newArrayList(value), time);
    }

    @Override
    public boolean lSet(String key, List<Object> value) {
        return lSet(key, value, 0);
    }

    @Override
    public boolean lSet(String key, List<Object> value, long time) {
        boolean added = redissonClient.getList(key).addAll(value);
        if (added && time > 0) {
            redissonClient.getList(key).expire(time, TimeUnit.SECONDS);
        }
        return added;
    }

    @Override
    public boolean lUpdateIndex(String key, int index, Object value) {
        redissonClient.getList(key).fastSet(index, value);
        return true;
    }

    @Override
    public boolean lRemove(String key, int count, Object value) {
        return redissonClient.getList(key).remove(value, count);
    }

    @Override
    public Collection<ScoredEntry<Object>> top(String key, int end) {
        return range(key, 0, end);
    }

    @Override
    public Collection<ScoredEntry<Object>> range(String key, int start, int end) {
        return redissonClient.getScoredSortedSet(key).entryRange(start, end);
    }

    /**
     * 加积分
     */
    @Override
    public void addScore(String key, String searchValue, int delta) {
        redissonClient.getScoredSortedSet(key).addAndGetRank(delta, searchValue);
    }

    @Override
    public <T> void addDelayQueue(String queueCode, T value, Long times, TimeUnit timeUnit) {
        RBlockingDeque<Object> rBlockingDeque = redissonClient.getBlockingDeque(queueCode);
        RDelayedQueue<Object> rDelayedQueue = redissonClient.getDelayedQueue(rBlockingDeque);
        if (dequeContains(rDelayedQueue, value)) {
            rDelayedQueue.remove(value);
        }
        rDelayedQueue.offer(value, times, timeUnit);
        log.info("延迟队列对象={},失效时间={},失效单位{}", JSON.toJSONString(value), times, timeUnit.name());
    }

    @Override
    public <T> T getDelayQueue(String queueCode) throws InterruptedException {
        RBlockingDeque<Object> rBlockingDeque = redissonClient.getBlockingDeque(queueCode);
        return (T) rBlockingDeque.take();
    }

    /**
     * @param rDelayedQueue
     * @param value
     * @param <T>
     * @return
     */
    private <T> boolean dequeContains(RDelayedQueue<Object> rDelayedQueue, T value) {
        return rDelayedQueue.contains(value);
    }

    @Override
    public <T> boolean publishMsg(String topic, T msg) {
        try {
            RTopic clientTopic = getTopic(topic);
            clientTopic.publishAsync(msg);
            return true;
        } catch (Exception e) {
            log.info("redis消息发布失败：{}", e.getMessage());
        }
        return false;
    }

    @Override
    public RTopic getTopic(String topic) {
        return redissonClient.getTopic(topic, new SerializationCodec());
    }


}
